package com.atguigu.tingshu.order.service.impl;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.account.client.UserAccountFeignClient;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.common.constant.KafkaConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.service.KafkaService;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.user.client.VipServiceConfigFeignClient;
import com.atguigu.tingshu.vo.account.AccountLockResultVo;
import com.atguigu.tingshu.vo.account.AccountLockVo;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;


import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Qualifier("com.atguigu.tingshu.user.client.UserInfoFeignClient")
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Qualifier("com.atguigu.tingshu.album.client.AlbumInfoFeignClient")
    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Qualifier("com.atguigu.tingshu.user.client.VipServiceConfigFeignClient")
    @Autowired
    private VipServiceConfigFeignClient vipServiceConfigFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;
    @Qualifier("com.atguigu.tingshu.account.client.UserAccountFeignClient")
    @Autowired
    private UserAccountFeignClient userAccountFeignClient;

    @Autowired
    private KafkaService kafkaService;

    @Autowired
    private OrderDerateMapper orderDerateMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private RedissonClient redissonClient;


    @Override
    public IPage<OrderInfo> findUserPage(Page<OrderInfo> pageParam, Long userId) {
        //  调用mapper 层方法
        IPage<OrderInfo> infoIPage = orderInfoMapper.selectUserPage(pageParam,userId);
        infoIPage.getRecords().forEach(item->{
            //  设置状态名
            item.setOrderStatusName(getOrderStatusName(item.getOrderStatus()));

            item.setPayWayName(getPayWayName(item.getPayWay()));
        });
        return infoIPage;
    }

    private String getPayWayName(String payWay) {
        //  声明订单状态名称
        String orderStatusName = "";
        //  判断
        if (SystemConstant.ORDER_PAY_WAY_WEIXIN.equals(payWay)){
            orderStatusName = "微信支付";
        } else if (SystemConstant.ORDER_PAY_WAY_ALIPAY.equals(payWay)) {
            orderStatusName = "支付宝支付";
        } else if (SystemConstant.ORDER_PAY_ACCOUNT.equals(payWay)) {
            orderStatusName = "余额支付";
        }else {
            orderStatusName = "已取消";
        }
        //  返回
        return orderStatusName;
    }


    private String getOrderStatusName(String orderStatus) {
        //  声明订单状态名称
        String orderStatusName = "";
        //  判断
        if (SystemConstant.ORDER_STATUS_UNPAID.equals(orderStatus)){
            orderStatusName = "未支付";
        } else if (SystemConstant.ORDER_STATUS_PAID.equals(orderStatus)) {
            orderStatusName = "已支付";
        } else {
            orderStatusName = "已取消";
        }
        //  返回
        return orderStatusName;
    }

    @Override
    public void orderCancel(long orderId) {
        OrderInfo orderInfoUpt = new OrderInfo();
        orderInfoUpt.setId(orderId);
        orderInfoUpt.setOrderStatus(SystemConstant.ORDER_STATUS_CANCEL);
        // 执行更新方法
        this.updateById(orderInfoUpt);
    }

    @Override
    public String submitOrder(OrderInfoVo orderInfoVo, Long userId) {
        //  校验签名
        Map map = JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class);
        map.put("payWay","");
        SignHelper.checkSign(map);

        //  验证校验好，防止重复提交订单
        String tradeNo = orderInfoVo.getTradeNo();
        if (StringUtils.isEmpty(tradeNo)){
            //  非法提交
            throw  new GuiguException(ResultCodeEnum.ILLEGAL_REQUEST);
        }
        String tradeNoKey = "user:trade:" + userId;
        String script = "if(redis.call('get', KEYS[1]) == ARGV[1]) then return redis.call('del', KEYS[1]) else return 0 end";
        Boolean flag = (Boolean) redisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class), Arrays.asList(tradeNoKey), tradeNo);
        if (!flag) {
            // 不能重复提交订单！
            throw new GuiguException(ResultCodeEnum.ORDER_SUBMIT_REPEAT);
        }
        String orderNo = UUID.randomUUID().toString().replace("-", "");
        //  支付类型
        if (!SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfoVo.getPayWay())){
            //  在线支付
            this.saveOrder(orderInfoVo,userId,orderNo);
        }else {
            try {
                //  锁定账户可用金额
                AccountLockVo accountLockVo = new AccountLockVo();
                accountLockVo.setOrderNo(orderNo);
                accountLockVo.setUserId(userId);
                accountLockVo.setAmount(orderInfoVo.getOrderAmount());
                accountLockVo.setContent(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
                Result<AccountLockResultVo> result = userAccountFeignClient.checkAndLock(accountLockVo);
                if (200 != result.getCode()){
                    throw  new GuiguException(result.getCode(),result.getMessage());
                }
                this.saveOrder(orderInfoVo,userId,orderNo);
                //  支付成功扣减账户金额
                kafkaService.sendMessage(KafkaConstant.QUEUE_ACCOUNT_MINUS, orderNo);
                //  返回订单编号
                return orderNo;
            }catch (GuiguException e){
                throw new GuiguException(e.getCode(),e.getMessage());
            }
            catch (Exception e){
                kafkaService.sendMessage(KafkaConstant.QUEUE_ACCOUNT_UNLOCK, orderNo);
                 throw new GuiguException(ResultCodeEnum.DATA_ERROR);
            }
        }
        return orderNo;
    }

    private void saveOrder(OrderInfoVo orderInfoVo, Long userId, String orderNo) {
        //  创建对象对象
        OrderInfo orderInfo = new OrderInfo();
        //  属性拷贝
        BeanUtils.copyProperties(orderInfoVo, orderInfo);
        orderInfo.setOrderNo(orderNo);
        String orderTitle = orderInfoVo.getOrderDetailVoList().get(0).getItemName();
        orderInfo.setOrderTitle(orderTitle);
        orderInfo.setUserId(userId);
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        //  保存订单
        orderInfoMapper.insert(orderInfo);

        // 订单明细
        if (!CollectionUtils.isEmpty(orderInfoVo.getOrderDetailVoList())) {
            List<OrderDetail> orderDetailList = new ArrayList<>();
            orderInfoVo.getOrderDetailVoList().forEach(orderDetailVo -> {
                OrderDetail orderDetail = new OrderDetail();
                BeanUtils.copyProperties(orderDetailVo, orderDetail);
                orderDetail.setOrderId(orderInfo.getId());
                orderDetailList.add(orderDetail);
                orderDetailMapper.insert(orderDetail);
            });
            orderInfo.setOrderDetailList(orderDetailList);
        }

        // 订单减免
        if (!CollectionUtils.isEmpty(orderInfoVo.getOrderDerateVoList())) {
            orderInfoVo.getOrderDerateVoList().forEach(orderDerateVo -> {
                OrderDerate orderDerate = new OrderDerate();
                BeanUtils.copyProperties(orderDerateVo, orderDerate);
                orderDerate.setOrderId(orderInfo.getId());
                orderDerateMapper.insert(orderDerate);
            });
        }

        if (SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfo.getPayWay())) {
            // 余额支付成功保存交易数据
            this.orderPaySuccess(orderNo,orderInfo);
        } else {
            // 发送延迟队列，如果定时未支付，取消订单
            this.sendDelayMessage(orderInfo.getId());
        }
    }

    private void sendDelayMessage(Long orderId) {
        try {
            //  创建一个队列
            RBlockingDeque<Object> blockingDeque = redissonClient.getBlockingDeque(KafkaConstant.QUEUE_ORDER_CANCEL);
            //  将队列放入延迟队列中
            RDelayedQueue<Object> delayedQueue = redissonClient.getDelayedQueue(blockingDeque);
            //  发送的内容  过了规定的时间，延时队列中的值才可以被取走
            delayedQueue.offer(orderId.toString(), KafkaConstant.DELAY_TIME, TimeUnit.SECONDS);
            log.info("添加延时队列成功 ，延迟时间：{}，订单id：{}", KafkaConstant.DELAY_TIME, orderId);
        } catch (Exception e) {
            log.error("添加延时队列失败 ，延迟时间：{}，订单id：{}", KafkaConstant.DELAY_TIME, orderId);
            e.printStackTrace();
        }
    }



    private void orderPaySuccess(String orderNo,OrderInfo orderInfo) {
        //  根据 orderNo 修改订单状态数据
        this.update(new LambdaUpdateWrapper<OrderInfo>().set(OrderInfo::getOrderStatus, SystemConstant.ORDER_STATUS_PAID).eq(OrderInfo::getOrderNo, orderNo));

        List<Long> itemIdList = orderInfo.getOrderDetailList().stream().map(OrderDetail::getItemId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(itemIdList)) {
            UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
            BeanUtils.copyProperties(orderInfo, userPaidRecordVo);
            userPaidRecordVo.setItemIdList(itemIdList);
            kafkaService.sendMessage(KafkaConstant.QUEUE_USER_PAY_RECORD, JSON.toJSONString(userPaidRecordVo));
        }
    }

    @Override
    public OrderInfoVo trade(TradeVo tradeVo, Long userId) {
        Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfoVo(userId);
        Assert.notNull(userInfoVoResult, "用户信息集为空");
        UserInfoVo userInfoVo = userInfoVoResult.getData();
        Assert.notNull(userInfoVo, "用户信息为空");
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        BigDecimal originalAmount = new BigDecimal("0.0");
        BigDecimal derateAmount = new BigDecimal("0.0");
        BigDecimal orderAmount = new BigDecimal("0.0");
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();
        if (tradeVo != null) {
            if (tradeVo.getItemType().equals("1001")) {
                //购买专辑

                Result<Boolean> isPaidAlbumResult = this.userInfoFeignClient.isPaidAlbum(tradeVo.getItemId());
                Assert.notNull(isPaidAlbumResult,"用户是否购买专辑接口异常");
                Boolean isPaidAlbum = isPaidAlbumResult.getData();
                Assert.notNull(isPaidAlbum,"用户是否购买专辑接口异常");
                if (isPaidAlbum){
                    throw new GuiguException(ResultCodeEnum.REPEAT_BUY_ERROR);
                }
                Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(tradeVo.getItemId());
                Assert.notNull(albumInfoResult, "专辑信息集不存在");
                AlbumInfo albumInfo = albumInfoResult.getData();
                Assert.notNull(albumInfo, "专辑信息不存在");
                if(userInfoVo.getIsVip()==1){
                    originalAmount=new BigDecimal(albumInfo.getPrice().toString());
                    if(albumInfo.getDiscount().intValue()!=-1){
                        derateAmount=albumInfo.getPrice()
                                .subtract(albumInfo.getPrice()
                                        .multiply(albumInfo.getDiscount().divide(new BigDecimal("10.0"))));
                    }
                    orderAmount=originalAmount.subtract(derateAmount);
                }else{
                    originalAmount=new BigDecimal(albumInfo.getPrice().toString());
                    if(albumInfo.getVipDiscount().intValue()!=-1){
                        derateAmount=albumInfo.getPrice()
                                .subtract(albumInfo.getPrice()
                                        .multiply(albumInfo.getVipDiscount().divide(new BigDecimal("10.0"))));
                    }
                    orderAmount=originalAmount.subtract(derateAmount);
                }

                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemId(tradeVo.getItemId());
                orderDetailVo.setItemName(albumInfo.getAlbumTitle());
                orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
                orderDetailVo.setItemPrice(albumInfo.getPrice());
                orderDetailVoList.add(orderDetailVo);

                if (originalAmount.subtract(orderAmount).doubleValue() != 0) {
                    OrderDerateVo orderDerateVo = new OrderDerateVo();
                    orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
                    orderDerateVo.setDerateAmount(originalAmount.subtract(orderAmount));
                    orderDerateVoList.add(orderDerateVo);
                }

            } else if (tradeVo.getItemType().equals("1002")) {
                //购买声音

            } else {
                //购买vip会员
                Result<VipServiceConfig> vipServiceConfigResult = vipServiceConfigFeignClient.getVipServiceConfig(tradeVo.getItemId());
                Assert.notNull(vipServiceConfigResult,"返回vip配置结果集不能为空");
                VipServiceConfig vipServiceConfig = vipServiceConfigResult.getData();
                Assert.notNull(vipServiceConfig,"返回vip配置对象不能为空");
                originalAmount = vipServiceConfig.getPrice();
                derateAmount = vipServiceConfig.getPrice().subtract(vipServiceConfig.getDiscountPrice());
                orderAmount = originalAmount.subtract(derateAmount);

                //订单明细
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemId(tradeVo.getItemId());
                orderDetailVo.setItemName("VIP会员"+vipServiceConfig.getName());
                orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
                orderDetailVo.setItemPrice(vipServiceConfig.getDiscountPrice());
                orderDetailVoList.add(orderDetailVo);

                //添加订单减免
                if (originalAmount.subtract(orderAmount).doubleValue() != 0) {
                    OrderDerateVo orderDerateVo = new OrderDerateVo();
                    orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
                    orderDerateVo.setDerateAmount(originalAmount.subtract(orderAmount));
                    orderDerateVoList.add(orderDerateVo);
                }
            }
        }
        orderInfoVo.setPayWay("");
        String s = UUID.randomUUID().toString().replaceAll("-", "");
        String tradeNoKey = "user:trade:" + userId;
        redisTemplate.opsForValue().set(tradeNoKey, s);
        orderInfoVo.setTradeNo(s);
        orderInfoVo.setItemType(tradeVo.getItemType());
        orderInfoVo.setOrderAmount(orderAmount);
        orderInfoVo.setOriginalAmount(originalAmount);
        orderInfoVo.setDerateAmount(derateAmount);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        orderInfoVo.setTimestamp(SignHelper.getTimestamp());
        String orderStr = JSONObject.toJSONString(orderInfoVo);
        Map map = JSON.parseObject(orderStr, Map.class);
        orderInfoVo.setSign(SignHelper.getSign(map));

        return orderInfoVo;
    }
}
